home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-11-02 | 50.1 KB | 1,407 lines |
- /*
- * fscheck.c --
- *
- * Perform consistency checks on a filesystem.
- *
- * Copyright 1989 Regents of the University of California
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The University of California
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- */
-
- #ifndef lint
- static char rcsid[] = "$Header: /sprite/src/cmds/fscheck/RCS/fscheck.c,v 1.37 90/11/01 23:27:34 jhh Exp $ SPRITE (Berkeley)";
- #endif not lint
-
- #include "option.h"
- #include "list.h"
- #include "fscheck.h"
- #include <string.h>
- #include <host.h>
- #include <sys/file.h>
- #include <sys/stat.h>
- #include <stdio.h>
-
- int numBlocks = 0;
- int numFiles = 0;
- int numBadDesc = 0;
- int numFrags = 0;
- int errorType = EXIT_OK;
- int foundError = 0;
- int fdBitmapError = 0;
- Boolean tooBig = FALSE;
- Ofs_DomainHeader *domainPtr;
- int partFID;
- Boolean patchHeader = FALSE;
- Boolean attached = FALSE;
-
- /*
- * The following are used to go from a command line like
- * fscheck -dev rsd0 -part b
- * to /dev/rsd0a - for the partition that has the disk label
- * and to /dev/rsd0b - for the partition to format.
- */
- char *deviceName; /* Set to "rsd0" or "rxy1", etc. */
- char *partName; /* Set to "a", "b", "c" ... "g" */
- char defaultFirstPartName[] = "a";
- char *firstPartName = defaultFirstPartName;
- char defaultDevDirectory[] = "/dev/";
- char *devDirectory = defaultDevDirectory;
- char *outputFileName = NULL;
-
- int hostID = -1;
- int writeDisk = 0;
- int verbose = 0;
- int silent = 0;
- int clearDomainNumber = 0;
- int recoveryCheck = 0;
- int badBlockInit = 0;
- int patchRoot = 0;
- int rawOutput = FALSE;
- int maxHeapSize = -1;
- int bufferSize = BUFSIZ;
- int heapSize = 0;
- int noCopy = FALSE;
- int blocksToRead = 1;
- int debug = FALSE;
- int clearFixCount = FALSE;
- int bitmapVerbose = 0;
- int numReboot = 4;
- int blockToFind = -1;
- int fileToPrint = -1;
- int dontRecheck = 0;
- int setCheckedBit = FALSE;
-
- Option optionArray[] = {
- {OPT_STRING, "dev", (Address)&deviceName,
- "Required: Name of device, eg \"rsd0\" or \"rxy1\""},
- {OPT_STRING, "part", (Address)&partName,
- "Required: Partition ID: (a, b, c, d, e, f, g)"},
- {OPT_STRING, "dir", (Address)&devDirectory,
- "Name of device directory (\"/dev/\")"},
- {OPT_STRING, "initialPart", (Address)&firstPartName,
- "Name of initial partition (\"a\")"},
- {OPT_TRUE, "write", (Address)&writeDisk,
- "Write disk "},
- {OPT_TRUE, "silent", (Address)&silent,
- "Don't say anything unless there's a problem "},
- {OPT_TRUE, "verbose", (Address)&verbose,
- "Output information about differences in bitmaps "},
- {OPT_TRUE, "fixRoot", (Address)&patchRoot,
- "Re-create the missing/corrupt root directory."},
- {OPT_TRUE, "clear", (Address)&clearDomainNumber,
- "Clear the domain number field stored in the summary sector"},
- {OPT_INT, "hostID", (Address)&hostID,
- "Update the host ID in the disk header"},
- {OPT_TRUE, "badBlock", (Address)&badBlockInit,
- "Initialize the bad block file descriptor"},
- {OPT_STRING, "outputFile", (Address)&outputFileName,
- "Name of file in which to store output."},
- {OPT_TRUE, "rawOutput", (Address) &rawOutput,
- "Bypass the filesystem when writing the output into the file."},
- {OPT_INT, "heapLimit", (Address)&maxHeapSize,
- "Maximum amount of dynamic storage allowed."},
- {OPT_INT, "bufferSize", (Address)&bufferSize,
- "Size of buffer for output file stream."},
- {OPT_TRUE, "delete", (Address)&noCopy,
- "Truncate files containing duplicate blocks."},
- {OPT_TRUE, "debug", (Address)&debug,
- "Print debugging information."},
- {OPT_INT, "readBlock", (Address)&blocksToRead,
- "Number of blocks to read at a time."},
- {OPT_TRUE, "clearFixCount", (Address)&clearFixCount,
- "Clear the count of consecutive disk fixes in summary sector"},
- {OPT_TRUE, "bitmapVerbose", (Address)&bitmapVerbose,
- "Print information about bitmap errors."},
- {OPT_INT, "numReboot", (Address)&numReboot,
- "Number of consecutive runs before returning EXIT_NOREBOOT"},
- {OPT_INT, "block", (Address)&blockToFind,
- "Block to look for"},
- {OPT_INT, "file", (Address)&fileToPrint,
- "File to print"},
- {OPT_TRUE, "cond", (Address)&dontRecheck,
- "Don't check the disk if it has just been checked successfully"},
- {OPT_TRUE, "setCheck", (Address)&setCheckedBit,
- "If the disk is checked and fixed ok set a bit in the summary sector"},
- };
- int numOptions = sizeof(optionArray) / sizeof(Option);
-
- /*
- * Forward Declarations.
- */
- void CheckFilesystem();
- int RecoveryCheck();
-
- /*
- * The last file that an error message was printed about.
- */
- int lastErrorFD = -1;
- int fixCount = 0;
-
-
- /*
- *----------------------------------------------------------------------
- *
- * main --
- *
- * Create the required file names from the command line
- * arguments. Then open the first partition on the disk
- * because it contains the disk label, and open the partition
- * that is to be checked.
- *
- * Results:
- *
- * Side effects:
- * File opening.
- *
- *----------------------------------------------------------------------
- */
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int firstPartFID;
- char firstPartitionName[64];
- char partitionName[64];
- int partition;
- u_char *streamBuffer;
- int outputFID;
- char *timeString;
- struct timeval tp;
- struct timezone tzp;
- int argsReturned;
-
-
- argsReturned = Opt_Parse(argc, argv, optionArray, numOptions, 0);
- if (argsReturned > 1) {
- Opt_PrintUsage(argv[0], optionArray, Opt_Number(optionArray));
- exit(EXIT_BAD_ARG);
- }
- /*
- * Set up stream for output to file, as well as output to stderr.
- */
- if (outputFileName == NULL) {
- outputFile = NULL;
- } else if (!rawOutput) {
- outputFile = fopen(outputFileName,"a+");
- if (outputFile == NULL ) {
- OutputPerror("fscheck: Can't open output file \"%s\\n",
- outputFileName);
- exit(EXIT_HARD_ERROR);
- }
- if (bufferSize != BUFSIZ) {
- if (setvbuf(outputFile,(char *) NULL,_IOFBF,bufferSize)) {
- Output(stderr,
- "fscheck: Unable to change output buffer size.\n");
- if (maxHeapSize > 0) {
- maxHeapSize -= bufferSize;
- }
- }
- }
- } else {
- if (bufferSize > FSDM_NUM_DIRECT_BLOCKS * FS_BLOCK_SIZE) {
- Output(stderr,
- "Maximum buffer size allowed when using raw output is %d bytes.\n",
- FSDM_NUM_DIRECT_BLOCKS * FS_BLOCK_SIZE);
- exit(EXIT_BAD_ARG);
- }
- Alloc(streamBuffer,u_char,bufferSize);
- Stdio_Setup(outputFile,0,1,streamBuffer,bufferSize,NULL,
- WriteOutputFile, CloseOutputFile,NULL);
- }
- if (rawOutput) {
- Output(stderr," \n");
- }
- gettimeofday(&tp,&tzp);
- timeString = asctime(localtime(&tp.tv_sec));
- if (verbose) {
- Output(stderr,"***** Fscheck *****\n");
- }
- if (!silent) {
- Output(stderr,"%s",timeString);
- }
- if (tooBig) {
- Output(stderr,"fscheck: Heap limit too small.\n");
- exit(EXIT_MORE_MEMORY);
- }
- if (deviceName == (char *)0) {
- Output(stderr, "Specify device name with -dev option\n");
- exit(EXIT_BAD_ARG);
- }
- if (partName == (char *)0) {
- Output(stderr, "Specify partition with -part option\n");
- exit(EXIT_BAD_ARG);
- }
- if (blocksToRead <= 0) {
- Output(stderr,"blocksToRead value %d illegal - using 1.\n");
- blocksToRead = 1;
- }
- if (patchRoot && !writeDisk) {
- Output(stderr,
- "Sorry but you can't patch the root without writing the disk.\n");
- exit(EXIT_BAD_ARG);
- }
- if (hostID != -1) {
- patchHeader = TRUE;
- }
- /*
- * Gen up the name of the first partition on the disk,
- * and the name of the partition that needs to be checked.
- */
- (void)strcpy(firstPartitionName, devDirectory); /* eg. /dev/ */
- (void)strcpy(partitionName, devDirectory);
- (void)strcat(firstPartitionName, deviceName); /* eg. /dev/rxy0 */
- (void)strcat(partitionName, deviceName);
- (void)strcat(firstPartitionName, firstPartName); /* eg. /dev/rxy0a */
- (void)strcat(partitionName, partName); /* eg. /dev/rxy0b */
-
- firstPartFID = open(firstPartitionName, O_RDONLY);
- if (firstPartFID < 0) {
- OutputPerror("fscheck: Can't open first partition");
- exit(EXIT_HARD_ERROR);
- }
- partFID = open(partitionName, writeDisk ? O_RDWR : O_RDONLY);
- if (partFID < 0) {
- OutputPerror("fscheck: Can't open partition to check ");
- exit(EXIT_HARD_ERROR);
- }
-
- partition = partName[0] - 'a';
- if (partition < 0 || partition > 7) {
- Output(stderr,
- "fscheck: Can't determine partition index from the partition name\n");
- exit(EXIT_BAD_ARG);
- }
- if ((maxHeapSize > 0) && (bufferSize >= maxHeapSize)) {
- Output(stderr,
- "fscheck: Size of output buffer exceeds maximum heap size.\n");
- exit(EXIT_MORE_MEMORY);
- }
- CheckFilesystem(firstPartFID, partFID, partition);
-
- if (outputFile != NULL) {
- (void)fclose(outputFile);
- }
- (void)close(firstPartFID);
- (void)close(partFID);
- if (foundError) {
- if (attached) {
- exit(EXIT_REBOOT);
- }
- if (errorType != EXIT_OK) {
- exit(errorType);
- }
- exit(EXIT_SOFT_ERROR);
- }
- exit(EXIT_OK);
- }
-
- unsigned char *fdBitmapPtr;
- unsigned char *cylBitmapPtr;
-
- /*
- * Array to provide the ability to set and extract bits out of a bitmap byte.
- */
- unsigned char bitmasks[BITS_PER_BYTE] = {
- 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1
- };
-
- void ReadDomainHeader();
- void CheckDirTree();
- void CheckBlocks();
- unsigned char *ReadFileDescBitmap();
- unsigned char *ReadBitmap();
- FdInfo *ReadFileDesc();
- void WriteDomainHeader();
- void WriteFileDescBitmap();
- void WriteBitmap();
- void WriteFileDesc();
- void WriteSummaryInfo();
- void CheckFDBitmap();
- void SetBadDescBitmap();
- void RelocateFD();
-
- int num1KBlocks;
- int bytesPerCylinder;
-
- List_Links copyListHdr;
- List_Links relocListHdr;
- List_Links modListHdr;
- #define tempCopyList &tempCopyListHdr;
-
-
- /*
- *----------------------------------------------------------------------
- *
- * CheckFilesystem --
- *
- * Perform consistency checks on the file system.
- *
- * Results:
- * An error code, probably from a read.
- *
- * Side effects:
- * Error flags may be set
- *
- *----------------------------------------------------------------------
- */
- void
- CheckFilesystem(firstPartFID, partFID, partition)
- int firstPartFID; /* Handle on the first partition of the disk */
- int partFID; /* Handle on the partition of the disk to format */
- int partition; /* Index of parition that is to be dumped */
- {
- Disk_Label *labelPtr;
- FdInfo *descInfoPtr;
- register FdInfo *tDescInfoPtr;
- unsigned char *tFdBitmapPtr;
- unsigned char *newCylBitmapPtr;
- int i, j, k;
- int fdNum;
- char *block;
- Fsdm_FileDescriptor *fdPtr;
- int sector;
- unsigned int validMask;
- int valid;
- int salvage;
- unsigned char *oldPtr;
- unsigned char *newPtr;
- int blockNum;
- int bitmapError = 0;
- RelocListElement *relocElemPtr;
- CopyListElement *copyElemPtr;
- Boolean blockModified;
- Fsdm_FileDescriptor *fdCopyPtr = NULL;
- Boolean copyUsed;
- Boolean batchRead;
- char *blockBuffer;
- Boolean blockBufferModified;
- int numFileDescBlocks;
- Boolean fdMagicOkay;
- int status;
-
-
-
- /*
- * Read the copy of the super block at the beginning of the partition
- * to find out basic disk geometry and where to find the domain header.
- */
- labelPtr = Disk_ReadLabel(firstPartFID);
- if (labelPtr == NULL) {
- Output(stderr, "CheckFilesystem: Could not read disk label\n");
- exit(EXIT_READ_FAILURE);
- }
- fflush(stderr);
- fflush(stdout);
- Alloc(blockBuffer, char, blocksToRead * FS_BLOCK_SIZE);
- if (tooBig) {
- Output(stderr,"CheckFileSystem: Heap limit too small.\n");
- exit(EXIT_MORE_MEMORY);
- }
- domainPtr = Disk_ReadDomainHeader(partFID, labelPtr);
- if (domainPtr == NULL) {
- Output(stderr, "CheckFilesystem: Could not read domain header\n");
- exit(EXIT_READ_FAILURE);
- }
- /*
- * See if we need to patch the host ID in the domain header.
- */
- if (patchHeader) {
- int spriteID;
- struct stat attrs;
-
- if (hostID != 0) {
- spriteID = hostID;
- } else {
- /*
- * Determine where the disk is located so we can set the
- * spriteID in the header correctly. If the disk device is generic
- * we use our own hostID, otherwise use the hostID specified
- * by the device file.
- */
- fstat(firstPartFID, &attrs);
- if (attrs.st_devServerID == FS_LOCALHOST_ID) {
- Proc_GetHostIDs((int *) NULL, &spriteID);
- } else {
- spriteID = attrs.st_devServerID;
- }
- }
- if (spriteID != domainPtr->device.serverID) {
- if (!silent) {
- Output(stderr, "Setting hostID in disk header to 0x%x\n",
- spriteID);
- }
- domainPtr->device.serverID = spriteID;
- } else {
- if (!silent) {
- Output(stderr, "Leaving hostID as 0x%x\n",spriteID);
- }
- patchHeader = FALSE;
- }
- } else if (debug) {
- Output(stderr,"HostID read off disk is 0x%x\n",
- domainPtr->device.serverID);
- }
- /*
- * Read in the file descriptor bit map and the cylinder bit map.
- */
- fdBitmapPtr = ReadFileDescBitmap(partFID, domainPtr);
- cylBitmapPtr = ReadBitmap(partFID, domainPtr);
- AllocByte(newCylBitmapPtr,unsigned char,domainPtr->bitmapBlocks *
- FS_BLOCK_SIZE);
- if (tooBig) {
- Output(stderr,"CheckFileSystem: Heap limit too small.\n");
- exit(EXIT_MORE_MEMORY);
- }
- bzero((Address)newCylBitmapPtr, domainPtr->bitmapBlocks * FS_BLOCK_SIZE);
- /*
- * Allocate the descriptor info array.
- */
- Alloc(descInfoPtr,FdInfo,domainPtr->numFileDesc);
- if (tooBig) {
- Output(stderr,"CheckFileSystem: Heap limit too small.\n");
- exit(EXIT_MORE_MEMORY);
- }
- bzero((Address)descInfoPtr, domainPtr->numFileDesc * sizeof(FdInfo));
-
- num1KBlocks = domainPtr->dataCylinders *
- domainPtr->geometry.blocksPerCylinder * FS_FRAGMENTS_PER_BLOCK;
- bytesPerCylinder = (domainPtr->geometry.blocksPerCylinder + 1) / 2;
- List_Init(modList);
- List_Init(relocList);
- List_Init(copyList);
-
- /*
- * Check the disk to see if the disk has been checked already.
- */
- if (verbose) {
- Output(stderr, "Performing recovery check\n");
- }
- status = RecoveryCheck(partFID, labelPtr);
- if (dontRecheck && status) {
- if (!silent) {
- Output(stderr,
- "Disk is marked as just checked. I won't bother checking it again.\n");
- }
- FindOutputFile();
- return;
- }
- /*
- * Recreate the file descriptor bit map and check the block counts and
- * make sure that all blocks are referenced. Also recreate the data block
- * bitmap.
- */
- if (verbose) {
- Output(stderr, "Checking file descriptors:\n");
- }
-
- tDescInfoPtr = descInfoPtr;
- tFdBitmapPtr = fdBitmapPtr;
- fdNum = 0;
- numFileDescBlocks = (domainPtr->numFileDesc + FSDM_FILE_DESC_PER_BLOCK - 1) /
- FSDM_FILE_DESC_PER_BLOCK;
- if (blocksToRead > numFileDescBlocks) {
- blocksToRead = numFileDescBlocks;
- }
- for (i = 0;
- (i < numFileDescBlocks) && !tooBig;
- i += blocksToRead) {
- batchRead = TRUE;
- if (Disk_BlockRead(partFID, domainPtr,
- domainPtr->fileDescOffset + i,
- blocksToRead, (Address) blockBuffer) < 0) {
- batchRead = FALSE;
- OutputPerror("CheckFilesystem: read of fd's failed");
- }
- block = blockBuffer;
- blockBufferModified = FALSE;
- for (k = 0; k < blocksToRead; k++) {
- if (batchRead) {
- block = &(blockBuffer[k * FS_BLOCK_SIZE]);
- salvage = 0;
- } else {
- /*
- * We couldn't read all of the disk blocks at once, so try
- * to read them one at a time.
- */
- if (Disk_BlockRead(partFID, domainPtr,
- domainPtr->fileDescOffset + i + k,
- 1, (Address) block) < 0) {
- /*
- * Hit a disk error reading the block. Read it a sector
- * at a time and try to salvage what we can.
- */
- OutputPerror("CheckFilesystem: BlockRead: Read failed");
- validMask = Disk_BadBlockRead(partFID, domainPtr,
- domainPtr->fileDescOffset + i + k,
- (Address) block);
- SetBadDescBitmap(domainPtr, fdNum, &tFdBitmapPtr);
- salvage = 1;
- }
- }
- if (!salvage) {
- CheckFDBitmap(domainPtr, fdNum, block, &tFdBitmapPtr);
- valid = 1;
- }
- blockModified = FALSE;
- for (sector = 0;
- sector < DISK_SECTORS_PER_BLOCK && !tooBig;
- sector++) {
- if (salvage) {
- valid = (validMask & (1 << sector)) != 0;
- numBadDesc++;
- }
- for (j = 0;
- j < FILE_DESC_PER_SECTOR &&
- fdNum < domainPtr->numFileDesc && !tooBig;
- j++, fdNum++, tDescInfoPtr++, fdPtr++) {
-
- int modified = 0;
- fdPtr = (Fsdm_FileDescriptor *)
- &block[(j + (FILE_DESC_PER_SECTOR * sector)) *
- FSDM_MAX_FILE_DESC_SIZE];
- if (fdPtr->magic != FSDM_FD_MAGIC) {
- if (!silent) {
- Output(stderr,
- "File %d has an invalid magic number <0x%x> and is being reset.\n",
- fdNum, fdPtr->magic);
- Output(stderr,
- "Current block is %d.\n",
- i + k + domainPtr->fileDescOffset);
- }
- UnmarkFDBitmap(fdNum,fdBitmapPtr);
- fdMagicOkay = FALSE;
- } else {
- fdMagicOkay = TRUE;
- }
- /*
- * Make a copy of the fd to be used by elements in
- * the lists. We have to do this because we can't keep
- * all of the fd's in memory at once.
- */
- if (fdCopyPtr == NULL) {
- Alloc(fdCopyPtr,Fsdm_FileDescriptor,1);
- if (tooBig) {
- continue;
- }
- }
- bcopy((Address)fdPtr, (Address)fdCopyPtr,
- sizeof(Fsdm_FileDescriptor));
- copyUsed = FALSE;
- relocElemPtr = NULL;
- copyElemPtr = NULL;
- if (salvage) {
- if (valid && fdMagicOkay &&
- (fdPtr->flags & FSDM_FD_ALLOC)) {
- /*
- * If the descriptor is valid and is in a disk block
- * that is bad, put the fd on a list for relocation.
- */
- Alloc(relocElemPtr,RelocListElement,1);
- if (tooBig) {
- continue;
- }
- tDescInfoPtr->flags |= FD_RELOCATE;
- relocElemPtr->origFdNum = fdNum;
- relocElemPtr->newFdNum = -1;
- relocElemPtr->fdPtr = fdCopyPtr;
- copyUsed = TRUE;
- }
- if (!valid) {
- tDescInfoPtr->flags |= FD_UNREADABLE;
- }
- }
- if (valid && fdMagicOkay) {
- if (fdPtr->fileType == FS_DIRECTORY) {
- tDescInfoPtr->flags |= IS_A_DIRECTORY;
- }
- if (fdPtr->flags & FSDM_FD_ALLOC) {
- tDescInfoPtr->flags |= FD_ALLOCATED;
- tDescInfoPtr->origLinkCount = fdPtr->numLinks;
-
- CheckBlocks(partFID, domainPtr, fdNum, fdCopyPtr,
- newCylBitmapPtr, &modified,©Used);
- if (modified) {
- blockModified = TRUE;
- }
- if (tooBig) {
- continue;
- }
- } else if (debug &&
- fdNum == FSDM_BAD_BLOCK_FILE_NUMBER &&
- fdPtr->firstByte == -1){
- Output(stderr,"bad block has been reset.\n");
- }
- }
- if ((badBlockInit && fdNum == FSDM_BAD_BLOCK_FILE_NUMBER) ||
- (salvage && !valid) || !(fdMagicOkay)) {
- if (badBlockInit &&
- fdNum == FSDM_BAD_BLOCK_FILE_NUMBER) {
- Output(stderr,
- "Clearing bad block file descriptor.\n");
- }
- ClearFd(fdMagicOkay ? FSDM_FD_ALLOC : FSDM_FD_FREE,
- fdCopyPtr);
- blockModified = TRUE;
- modified = 1;
- }
- if (relocElemPtr != NULL) {
- List_Insert((List_Links *)relocElemPtr,
- LIST_ATREAR(relocList));
- }
- if (modified) {
- bcopy((Address)fdCopyPtr, (Address)fdPtr,
- sizeof(Fsdm_FileDescriptor));
- fdPtr->version++;
- }
- if (copyUsed) {
- fdCopyPtr = NULL;
- }
- }
- }
- if (blockModified) {
- blockBufferModified = TRUE;
- if (!batchRead && writeDisk) {
- if (Disk_BlockWrite(partFID, domainPtr,
- domainPtr->fileDescOffset + i + k,
- 1, (Address) block) < 0) {
- OutputPerror("CheckFileSystem: FD write failed");
- exit(EXIT_WRITE_FAILURE);
- }
- }
- }
- }
- if (batchRead && blockBufferModified && writeDisk) {
- if (Disk_BlockWrite(partFID, domainPtr,
- domainPtr->fileDescOffset + i,
- blocksToRead, (Address) blockBuffer) < 0) {
- OutputPerror("CheckFileSystem: FD write failed");
- exit(EXIT_WRITE_FAILURE);
- }
- }
- }
- if (!silent && fdBitmapError) {
- Output(stderr, "Found error in file descriptor bitmap\n");
- }
-
-
- /*
- * We now know which descriptors, if any, need to be relocated. Allocate
- * new descriptors to hold the information.
- */
-
- if (!(List_IsEmpty(relocList))) {
- LIST_FORALL(relocList, (List_Links *)relocElemPtr) {
- RelocateFD(domainPtr, descInfoPtr, relocElemPtr);
- }
- }
- /*
- * Fix all blocks that appeared in more than one file.
- */
- if (!(List_IsEmpty(copyList))) {
- int status = 0;
-
- if (verbose) {
- Output(stderr, "\nCopying duplicate blocks\n");
- }
- LIST_FORALL(copyList, (List_Links *)copyElemPtr) {
- List_Remove((List_Links *) copyElemPtr);
- if (status != -1 && !noCopy) {
- status = CopyBlock(domainPtr, descInfoPtr, partFID,
- newCylBitmapPtr, copyElemPtr);
- }
- if ((copyElemPtr->parentType == FD) &&
- !((descInfoPtr[copyElemPtr->parentNum].flags &
- (ON_MOD_LIST | FD_RELOCATE)))) {
- free((Address) copyElemPtr->fdPtr);
- }
- free((Address) copyElemPtr);
- }
- }
- /*
- * Go through the file system starting at the root and perform a
- * consistency check.
- */
- if (!tooBig) {
- if (verbose) {
- Output(stderr, "Traversing directory tree:\n\n");
- }
-
- CheckDirTree(partFID, domainPtr, descInfoPtr, fdBitmapPtr,
- newCylBitmapPtr);
- } else {
- Output(stderr,
- "NOT traversing directory tree because heap limit exceeded.\n"
- );
- }
- /*
- * Now compare the two data block bitmaps.
- */
- if (verbose) {
- Output(stderr, "Comparing old and new data block bit maps:\n");
- }
- /*
- * Block 0 is reserved for the root directory, so mark it as in use.
- * There is code in the file system that will panic if block 0 is
- * reallocated.
- */
- if ((*cylBitmapPtr & 0xf0) != 0xf0) {
- if (!silent) {
- Output(stderr, "Block 0 is free. Marking it used.\n");
- }
- foundError = 1;
- bitmapError = 1;
- }
- *newCylBitmapPtr |= 0xf0;
- *cylBitmapPtr |= 0xf0;
- for (oldPtr = cylBitmapPtr, newPtr = newCylBitmapPtr, i = 0, blockNum = 0;
- i < domainPtr->dataCylinders;
- i++, oldPtr = &cylBitmapPtr[bytesPerCylinder * i],
- newPtr = &newCylBitmapPtr[bytesPerCylinder * i]) {
- for (j = 0;
- j < bytesPerCylinder;
- j++, oldPtr++, newPtr++, blockNum += 2) {
- if ((*oldPtr & 0xf0) != (*newPtr & 0xf0)) {
- if (bitmapVerbose) {
- Output(stderr,"Block %d: old %x new %x.\n",
- blockNum * FS_FRAGMENTS_PER_BLOCK,
- (*oldPtr & 0xf0) >> 4, (*newPtr & 0xf0) >> 4);
- }
- foundError = 1;
- bitmapError = 1;
- }
- if ((*oldPtr & 0x0f) != (*newPtr & 0x0f)) {
- if (bitmapVerbose) {
- Output(stderr,"Block %d: old %x new %x.\n",
- (blockNum + 1) * FS_FRAGMENTS_PER_BLOCK,
- *oldPtr & 0x0f, *newPtr & 0x0f);
- }
- foundError = 1;
- bitmapError = 1;
- }
- }
- }
- if (!silent && bitmapError) {
- Output(stderr, "Found error in data block bitmap\n");
- }
- fflush(stderr);
-
- /*
- * Print status information about disk.
- */
- Output(stdout,
- "%d files, %d blocks in use, %d blocks free, %d fragments\n",
- numFiles, numBlocks, domainPtr->dataBlocks * 4 - numBlocks,
- numFrags);
-
-
- if (foundError) {
- fixCount++;
- if (fixCount > numReboot) {
- foundError = 1;
- errorType = EXIT_NOREBOOT;
- }
- } else {
- fixCount = 0;
- }
- if (!writeDisk) {
- return;
- }
-
- if (verbose) {
- Output(stderr, "Writing disk\n");
- }
- fflush(stderr);
-
- /*
- * Write the file descriptor and data block bitmaps back out along with
- * the file descriptors.
- */
- if (patchHeader) {
- status = Disk_WriteDomainHeader(partFID, labelPtr, domainPtr);
- if (status != 0) {
- Output(stderr, "Unable to write domain header.\n");
- exit(EXIT_WRITE_FAILURE);
- }
- }
-
- WriteFileDescBitmap(partFID, domainPtr, fdBitmapPtr);
- WriteBitmap(partFID, domainPtr, newCylBitmapPtr);
-
- /*
- * Write out any modified file descriptors on the modified list.
- */
- WriteFileDesc(partFID, domainPtr, modList, descInfoPtr);
- WriteFileDesc(partFID, domainPtr, relocList, descInfoPtr);
- WriteSummaryInfo(partFID, labelPtr, domainPtr,
- numBlocks, numFiles);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * CheckBlocks --
- *
- * Check all the blocks associated with a file descriptor.
- *
- *
- * Results:
- * None.
- *
- * Side effects:
- * Error flags may be set.
- *
- *----------------------------------------------------------------------
- */
- void
- CheckBlocks(partFID, domainPtr, fdNum, fdPtr, newCylBitmapPtr, modifiedPtr,
- copyUsedPtr)
- int partFID; /* Raw handle on disk. */
- Ofs_DomainHeader *domainPtr; /* Ptr to domain info. */
- int fdNum; /* File descriptor # to check.*/
- Fsdm_FileDescriptor *fdPtr; /* Ptr to file descriptor that
- * are checking. */
- unsigned char *newCylBitmapPtr; /* Pointer to the disk block
- * bit map. */
- int *modifiedPtr; /* TRUE => modified the file */
- Boolean *copyUsedPtr; /* TRUE => copy of fd was stored * somewhere. */
- {
- register int *indexPtr;
- register int i, j;
- static int *dblIndirectBlock[FSDM_INDICES_PER_BLOCK];
- int indBlock;
- int lastBlock;
- int lastFrag;
- int tBlock;
- int dirty;
- int lastRealBlock;
- int blockCount = 0;
- int status = 0;
- Boolean duplicate;
- int virtualIndex;
-
- if (!(fdPtr->flags & FSDM_FD_ALLOC)) {
- return;
- }
- numFiles++;
- lastRealBlock = -1;
- /*
- * -1 is an empty file, anything less is an error.
- */
- if (fdPtr->lastByte < -1) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr, "File %d has bogus size %d. Setting to -1.\n",
- fdNum, fdPtr->lastByte);
- }
- fdPtr->lastByte = -1;
- foundError = 1;
- *modifiedPtr = 1;
- }
- if (fdPtr->lastByte == -1) {
- lastBlock = -1;
- lastFrag = FS_FRAGMENTS_PER_BLOCK - 1;
- } else {
- lastBlock = fdPtr->lastByte / FS_BLOCK_SIZE;
- if (lastBlock < FSDM_NUM_DIRECT_BLOCKS) {
- lastFrag = (fdPtr->lastByte & FS_BLOCK_OFFSET_MASK) / FS_FRAGMENT_SIZE;
- } else {
- lastFrag = FS_FRAGMENTS_PER_BLOCK - 1;
- }
- }
-
- /*
- * First check direct blocks. Loop through them first and see if the
- * file size corresponds to the number of blocks.
- */
- for (i = 0; i < FSDM_NUM_DIRECT_BLOCKS; i++) {
- if (i > lastBlock && fdPtr->direct[i] != FSDM_NIL_INDEX) {
- lastBlock++;
- fdPtr->lastByte += FS_BLOCK_SIZE;
- foundError = 1;
- *modifiedPtr = 1;
- if (lastFrag != FS_FRAGMENTS_PER_BLOCK - 1) {
- fdPtr->lastByte += (FS_FRAGMENTS_PER_BLOCK -1 - lastFrag) *
- FS_FRAGMENT_SIZE;
- lastFrag = FS_FRAGMENTS_PER_BLOCK - 1;
- }
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr,
- "Found a direct block beyond end of file %d. Increasing file size.\n",
- fdNum);
- lastErrorFD = fdNum;
- }
- }
- }
- for (i = 0; i < FSDM_NUM_DIRECT_BLOCKS; i++) {
- if (fileToPrint == fdNum) {
- Output(stderr, "File %d, d[%d] = %d.\n", fdNum, i,
- fdPtr->direct[i]);
- }
- if (fdPtr->direct[i] != FSDM_NIL_INDEX) {
- if (blockToFind == fdPtr->direct[i]) {
- Output(stderr, "Block %d is d[%d] in file %d.\n",
- fdPtr->direct[i], i, fdNum);
- }
- if (i == lastBlock) {
- status = MarkBitmap(fdNum, fdPtr->direct[i],
- newCylBitmapPtr,
- lastFrag + 1, domainPtr);
- if (status >= 0) {
- if (lastFrag + 1 != FS_FRAGMENTS_PER_BLOCK) {
- numFrags++;
- }
- blockCount += lastFrag + 1;
- numBlocks += lastFrag + 1;
- }
- } else {
- if (fdPtr->direct[i] &
- (FS_FRAGMENTS_PER_BLOCK - 1)) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr,
- "Block pointer %d invalid in direct block %d of file %d. Block deleted.\n",
- fdPtr->direct[i],i,fdNum);
- lastErrorFD = fdNum;
- }
- foundError = 1;
- status = -1;
- } else {
- status = MarkBitmap(fdNum, fdPtr->direct[i],
- newCylBitmapPtr,
- FS_FRAGMENTS_PER_BLOCK, domainPtr);
- if (status >= 0) {
- blockCount += FS_FRAGMENTS_PER_BLOCK;
- numBlocks += FS_FRAGMENTS_PER_BLOCK;
- }
- }
- }
- /*
- * Current block is also used by another file. Put info in copy
- * list so block is copied.
- */
- if (status == 1) {
- if (!tooBig) {
- AddToCopyList(FD,fdPtr,fdNum,0,i,DIRECT,
- (i == lastBlock) ? lastFrag + 1 :
- FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
- }
- }
- if (status < 0) {
- fdPtr->direct[i] = FSDM_NIL_INDEX;
- if (fdPtr->fileType == FS_DIRECTORY) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr,
- "Hole in directory %d at direct block %d.\n", fdNum,
- i);
- lastErrorFD = fdNum;
- }
- AddToCopyList(FD,fdPtr,fdNum,0,i,DIRECT,
- (i == lastBlock) ? lastFrag + 1 :
- FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
- }
- } else {
- lastRealBlock = i;
- if (i == lastBlock) {
- break;
- }
- }
- } else if (fdPtr->fileType == FS_DIRECTORY) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr, "Hole in directory %d at direct block %d.\n",
- fdNum, i);
- lastErrorFD = fdNum;
- }
- AddToCopyList(FD,fdPtr,fdNum,0,i,DIRECT,
- (i == lastBlock) ? lastFrag + 1 :
- FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
- }
- }
- /*
- * Now check the singly indirect block.
- */
- if (fdPtr->indirect[0] == FSDM_NIL_INDEX) {
- if (fdPtr->fileType == FS_DIRECTORY &&
- lastBlock > FSDM_NUM_DIRECT_BLOCKS) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr,
- "Hole in directory %d at single indirect block\n",
- fdNum);
- lastErrorFD = fdNum;
- }
- AddToCopyList(FD,fdPtr,fdNum,0,FSDM_NUM_DIRECT_BLOCKS,INDIRECT,
- FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
- }
- i += FSDM_INDICES_PER_BLOCK;
- } else {
- tBlock = i;
- status = ProcessIndirectBlock(fdNum, partFID,lastBlock, FALSE, fdPtr,
- &fdPtr->indirect[0], newCylBitmapPtr,
- domainPtr,&tBlock, &dirty,
- &lastRealBlock, modifiedPtr, &blockCount,
- copyUsedPtr);
- i = tBlock;
- /*
- * We need to copy block
- */
- if (status == 1) {
- AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS, INDIRECT,
- FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
- }
- if (status < 0) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr,
- "Hole in directory %d at single indirect block\n",
- fdNum);
- lastErrorFD = fdNum;
- }
- AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS, INDIRECT,
- FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
- }
- }
- if (fdPtr->indirect[1] == FSDM_NIL_INDEX) {
- goto checkBlockCount;
- }
-
- /*
- * Now check doubly indirect blocks.
- */
- indBlock = fdPtr->indirect[1];
- if (indBlock & (FS_FRAGMENTS_PER_BLOCK - 1)) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr,
- "Doubly indirect block %d on non-block boundary in file %d. Block deleted.\n",
- indBlock, fdNum);
- lastErrorFD = fdNum;
- setCheckedBit = FALSE;
- }
- foundError = 1;
- status = -1;
- } else {
- status = MarkBitmap(fdNum, PhysToVirt(domainPtr, indBlock),
- newCylBitmapPtr,
- FS_FRAGMENTS_PER_BLOCK, domainPtr);
- }
- if (status >= 0) {
- if (Disk_BlockRead(partFID, domainPtr,
- indBlock / FS_FRAGMENTS_PER_BLOCK,
- 1, (Address) dblIndirectBlock) < 0) {
- OutputPerror("CheckBlocks: Read failed");
- fdPtr->indirect[1] = FSDM_NIL_INDEX;
- *modifiedPtr = 1;
- goto truncFile;
- }
- /*
- * Look over contents of block first and see if they make sense.
- */
- for (j = 0, indexPtr = (int *) dblIndirectBlock;
- j < FSDM_INDICES_PER_BLOCK;
- j++, indexPtr++) {
- if (*indexPtr != FSDM_NIL_INDEX) {
- virtualIndex = PhysToVirt(domainPtr, *indexPtr);
- if (virtualIndex < 0 || virtualIndex >= num1KBlocks) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr,
- "Double indirect block %d of file %d contains garbage index %d\n",
- indBlock, fdNum, *indexPtr);
- lastErrorFD = fdNum;
- }
- fdPtr->indirect[1] = FSDM_NIL_INDEX;
- setCheckedBit = FALSE;
- *modifiedPtr = 1;
- goto truncFile;
- } else if ( i + j * FSDM_INDICES_PER_BLOCK > lastBlock) {
- lastBlock = i + j * FSDM_INDICES_PER_BLOCK;
- fdPtr->lastByte += FS_BLOCK_SIZE * FSDM_INDICES_PER_BLOCK;
- *modifiedPtr = 1;
- }
-
- }
- }
- duplicate = FALSE;
- if (status == 1) {
- duplicate = TRUE;
- AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS + 1,
- DBL_INDIRECT, FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
- }
- for (j = 0, indexPtr = (int *) dblIndirectBlock;
- j < FSDM_INDICES_PER_BLOCK && i <= lastBlock;
- j++, indexPtr++) {
- if (*indexPtr == FSDM_NIL_INDEX) {
- if (fdPtr->fileType == FS_DIRECTORY) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr,
- "Hole in directory %d in doubly indirect block\n",
- fdNum);
- lastErrorFD = fdNum;
- }
- AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS + 1,
- DBL_INDIRECT, FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
- }
- i += FSDM_INDICES_PER_BLOCK;
- continue;
- }
- tBlock = i;
- status = ProcessIndirectBlock(fdNum, partFID, lastBlock, duplicate,
- fdPtr, indexPtr, newCylBitmapPtr,
- domainPtr, &tBlock, &dirty,
- &lastRealBlock, modifiedPtr,
- &blockCount, copyUsedPtr);
- i = tBlock;
- if (status < 0) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr,
- "Hole in directory %d in doubly indirect blocks (2)\n",
- fdNum);
- lastErrorFD = fdNum;
- }
- AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS + 1,
- DBL_INDIRECT, FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
- }
- }
- if (status == 1 && !duplicate) {
- AddToCopyList(BLOCK, fdPtr, 0, indBlock, j, INDIRECT,
- FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
- }
- if (dirty) {
- if (writeDisk) {
- if (Disk_BlockWrite(partFID, domainPtr,
- indBlock / FS_FRAGMENTS_PER_BLOCK,
- 1, (Address) dblIndirectBlock) < 0) {
- OutputPerror("CheckBlocks: Write failed");
- exit(EXIT_WRITE_FAILURE);
- }
- }
- }
- numBlocks += FS_FRAGMENTS_PER_BLOCK;
- blockCount += FS_FRAGMENTS_PER_BLOCK;
-
- } else {
- if (fdPtr->fileType == FS_DIRECTORY) {
- AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS + 1,
- DBL_INDIRECT, FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
- } else {
- fdPtr->indirect[1] = FSDM_NIL_INDEX;
- *modifiedPtr = 1;
- }
- }
-
- if (lastRealBlock == lastBlock) {
- goto checkBlockCount;
- }
-
- truncFile:
-
- if (lastRealBlock != -1) {
- fdPtr->lastByte = (lastRealBlock + 1) * FS_BLOCK_SIZE - 1;
- } else {
- fdPtr->lastByte = -1;
- }
- Output(stderr,"Truncating file %d to length %d\n", fdNum,
- fdPtr->lastByte + 1);
- foundError = 1;
- *modifiedPtr = 1;
-
- checkBlockCount:
-
- if (blockCount != fdPtr->numKbytes) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr,
- "Block count corrected for file %d. Is %d should be %d.\n",
- fdNum, fdPtr->numKbytes, blockCount);
- lastErrorFD = fdNum;
- }
- fdPtr->numKbytes = blockCount;
- foundError = 1;
- *modifiedPtr = 1;
- }
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * ProcessIndirectBlock --
- *
- * Scan through the file descriptors in the indirect block and
- * update the cylinder map to reflect which blocks are allocated.
- *
- * Results:
- * -1 if found a hole in an indirect block for a directory
- * 1 if block is already in use
- * 0 otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- int
- ProcessIndirectBlock(fdNum, partFID,lastBlock,duplicate, fdPtr, blockNumPtr,
- newCylBitmapPtr,domainPtr,fileBlockNumPtr, dirtyPtr,
- lastRealBlockPtr, modifiedPtr, blockCountPtr,
- copyUsedPtr)
- int fdNum; /* Number of file descriptor that
- indirect block is in. */
- register Fsdm_FileDescriptor *fdPtr; /* Actual file descriptor. */
- int *blockNumPtr; /* Pointer to indirect block number */
- unsigned char *newCylBitmapPtr; /* The cylinder bit map to set bits
- in for allocated blocks. */
- int partFID; /* File id to use to read in indirect
- blocks from disk. */
- Ofs_DomainHeader *domainPtr; /* Domain to read from. */
- int lastBlock; /* The last block in the file. */
- int *fileBlockNumPtr; /* Pointer to file block number. */
- int *dirtyPtr; /* 1 if *blockNumPtr gets
- modified. */
- int *lastRealBlockPtr; /* Pointer to the number of the last
- valid block that was found for the
- file. */
- int *modifiedPtr; /* 1 if the file descriptor
- is modified. */
- int *blockCountPtr; /* Count of the number of blocks in
- * the file. */
- Boolean *copyUsedPtr; /* TRUE => copy of fd was stored
- * somewhere and should not be
- * reused. */
- Boolean duplicate; /* TRUE => we are processing a
- * duplicate block, therefore all
- * direct blocks will also be
- * duplicates. */
- {
- static char indirectBlock[FS_BLOCK_SIZE];
- int *indexPtr;
- int i;
- int dirty = 0;
- int status;
- int tempFileBlock;
- Boolean foundDuplicate = FALSE;
- int zeroCount;
-
-
-
- if (*blockNumPtr & (FS_FRAGMENTS_PER_BLOCK - 1)) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr,
- "Indirect block on a non-block boundary for file %d. Block deleted.\n",
- fdNum);
- lastErrorFD = fdNum;
- }
- foundError = 1;
- status = -1;
- } else {
- status = MarkBitmap(fdNum, PhysToVirt(domainPtr, *blockNumPtr),
- newCylBitmapPtr,
- FS_FRAGMENTS_PER_BLOCK, domainPtr);
- }
- if (status == 0) {
- /*
- * FIXME: need to be able to flag this as a bad block on error.
- */
- status = Disk_BlockRead(partFID, domainPtr,
- *blockNumPtr / FS_FRAGMENTS_PER_BLOCK, 1,
- (Address) indirectBlock);
- if (status < 0) {
- OutputPerror("ProcessIndirectBlock: Read failed");
- }
- } else if (status == 1 ) {
- foundDuplicate = TRUE;
- }
- if (status < 0) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr,
- "Indirect block (%d) unreadable for file #%d. Block deleted.\n",
- *blockNumPtr, fdNum);
- lastErrorFD = fdNum;
- }
- *fileBlockNumPtr += FSDM_INDICES_PER_BLOCK;
- *blockNumPtr = FSDM_NIL_INDEX;
- *dirtyPtr = 1;
- *modifiedPtr = 1;
- setCheckedBit = FALSE;
- return(0);
- } else {
- *dirtyPtr = 0;
- }
- /*
- * Look over contents of block first and see if they make sense.
- */
- zeroCount = 0;
- for (i = 0, indexPtr = (int *) indirectBlock,
- tempFileBlock = *fileBlockNumPtr;
- i < FSDM_INDICES_PER_BLOCK;
- i++, tempFileBlock++, indexPtr++) {
- if (*indexPtr != FSDM_NIL_INDEX) {
- if (*indexPtr == 0) {
- zeroCount++;
- continue;
- }
- if (*indexPtr == blockToFind) {
- Output(stderr, "Block %d is i[%d] in file %d.\n",
- *indexPtr, i, fdNum);
- }
- if (*indexPtr < 0 || *indexPtr >= num1KBlocks) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr,
- "Indirect block %d of file %d contains garbage index %d\n",
- *blockNumPtr, fdNum, *indexPtr);
- lastErrorFD = fdNum;
- setCheckedBit = FALSE;
- }
- *fileBlockNumPtr += FSDM_INDICES_PER_BLOCK;
- *blockNumPtr = FSDM_NIL_INDEX;
- *dirtyPtr = 1;
- *modifiedPtr = 1;
- foundError = 1;
- if (fdPtr->fileType == FS_DIRECTORY) {
- return(-1);
- } else {
- return(0);
- }
- } else if (tempFileBlock > lastBlock) {
- lastBlock = tempFileBlock;
- fdPtr->lastByte = tempFileBlock * FS_BLOCK_SIZE -1;
- *modifiedPtr = 1;
- }
- }
- }
- if (zeroCount == FSDM_INDICES_PER_BLOCK) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr, "Indirect block %d is all zeros.\n",
- *blockNumPtr, *indexPtr);
- lastErrorFD = fdNum;
- }
- *fileBlockNumPtr += FSDM_INDICES_PER_BLOCK;
- *blockNumPtr = FSDM_NIL_INDEX;
- *dirtyPtr = 1;
- *modifiedPtr = 1;
- foundError = 1;
- setCheckedBit = FALSE;
- if (fdPtr->fileType == FS_DIRECTORY) {
- return(-1);
- } else {
- return(0);
- }
- }
- numBlocks += FS_FRAGMENTS_PER_BLOCK;
- *blockCountPtr += FS_FRAGMENTS_PER_BLOCK;
- for (i = 0, indexPtr = (int *) indirectBlock;
- i < FSDM_INDICES_PER_BLOCK && *fileBlockNumPtr <= lastBlock;
- i++, (*fileBlockNumPtr)++, indexPtr++) {
-
- if (*indexPtr == FSDM_NIL_INDEX) {
- if (fdPtr->fileType == FS_DIRECTORY) {
- AddToCopyList(BLOCK, fdPtr, 0,
- *blockNumPtr, i, DIRECT,
- FS_FRAGMENTS_PER_BLOCK,
- copyUsedPtr);
- }
- continue;
- }
- if (*indexPtr & (FS_FRAGMENTS_PER_BLOCK - 1)) {
- if (verbose || lastErrorFD != fdNum) {
- Output(stderr,
- "Non-direct block fragmented for file %d. Block deleted.\n",
- fdNum);